前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# 本地路径处理 path

30 秒速记

  • path.join 只拼接 + 规范化,结果可能是相对路径;path.resolve 从右往左拼,直到凑出绝对路径,不够就补 process.cwd()
  • join('/a', '/b') = /a/b,resolve('/a', '/b') = /b,这是两者最直观的区别
  • 相对路径默认相对 process.cwd(),不是相对文件所在目录;要稳定就基于 __dirname
  • __dirname 只在 CommonJS 有;ESM 用 import.meta.dirname(Node 20.11+)或 fileURLToPath(import.meta.url)
  • 用户传的路径先 resolve 再检查没逃出根目录,防 ../../etc/passwd

path 模块就是用来正确拼接和解析文件路径的,最常用的是 join 和 resolve,两者看着像,语义不一样。 join 只是把片段用当前系统的分隔符连起来并清理掉 ..、多余斜杠,结果可能还是相对路径;resolve 像在终端里依次 cd,从右往左拼,遇到绝对路径就停,最后还不是绝对路径就补上当前工作目录。写脚本时最常见的坑是相对路径相对的是 process.cwd(),换个目录执行就找不到文件,所以我一般用 path.join(__dirname, 'xxx') 定位。

const path = require('path')
path.join('/a', 'b', '../c')     // '/a/c'
path.join('/a', '/b')            // '/a/b'
path.resolve('/a', '/b')         // '/b'  遇到绝对路径就重新开始
path.resolve('src')              // '/当前工作目录/src'
path.join('src')                 // 'src'  仍是相对路径
@前端进阶之旅: 代码已经复制到剪贴板

理解「本地路径处理 path」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 filesystem 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

path 模块处理的是路径字符串,不碰文件系统,所以它不会告诉你文件存不存在,只负责把路径算对。日常最常用的几个 API:

const path = require('path')
const file = '/home/user/project/src/index.test.js'

path.dirname(file)    // '/home/user/project/src'
path.basename(file)   // 'index.test.js'
path.basename(file, '.js') // 'index.test'
path.extname(file)    // '.js'  只取最后一个点之后的部分
path.parse(file)      // { root: '/', dir: '/home/user/project/src', base: 'index.test.js', ext: '.js', name: 'index.test' }

path.relative('/a/b/c', '/a/d') // '../../d'
path.isAbsolute('./x')          // false
path.sep                        // POSIX 下是 '/',Windows 下是 '\\'
@前端进阶之旅: 代码已经复制到剪贴板

join 和 resolve 的区别可以这样记:join 是「拼字符串再整理」,resolve 是「模拟一路 cd 之后所在的位置」。所以 path.resolve('a', 'b') 会得到 process.cwd() 开头的绝对路径,而 path.join('a', 'b') 只是 a/b。

脚本里定位文件时,最容易出错的是「相对路径到底相对谁」。fs.readFileSync('./config.json') 里的 ./ 相对的是启动进程时所在的目录,不是这个 JS 文件所在的目录。同一个脚本,在项目根目录执行能找到,换到上一级目录执行就找不到。解决办法是基于文件自身位置拼路径:

// CommonJS
const configPath = path.join(__dirname, 'config.json')

// ESM,Node 20.11+
const configPath2 = path.join(import.meta.dirname, 'config.json')

// ESM,更老的版本
import { fileURLToPath } from 'node:url'
const dir = path.dirname(fileURLToPath(import.meta.url))
@前端进阶之旅: 代码已经复制到剪贴板

处理用户输入的路径(比如静态文件服务、上传下载)时,一定要先算出绝对路径,再确认它还在允许的根目录里:

function safeJoin(root, userPath) {
  const target = path.resolve(root, userPath)
  const rel = path.relative(root, target)
  if (rel.startsWith('..') || path.isAbsolute(rel)) throw new Error('非法路径')
  return target
}
safeJoin('/srv/static', 'img/a.png')        // '/srv/static/img/a.png'
safeJoin('/srv/static', '../../etc/passwd') // 抛错
@前端进阶之旅: 代码已经复制到剪贴板

跨平台方面,path 默认按当前系统的规则工作。如果要在 Linux 上测试 Windows 路径,或者需要始终输出 / 分隔的 URL 风格路径,可以显式使用 path.win32 和 path.posix。

面试官追问

追问 1在 macOS 上能找到模板文件,Windows 的 CI 上找不到,常见原因是什么?
参考回答

多半是手拼了 'src/' + name 或写死了 /,再就是文件名大小写,macOS 默认不区分大小写,Linux 区分。拼路径一律用 path.join,比较路径前先 path.normalize。

追问 2用户传了 ../../etc/passwd 当文件名,怎么防?
参考回答

先 const target = path.resolve(root, input),再检查 target.startsWith(root + path.sep),不满足就拒绝。只过滤 .. 字符串不够,还有 URL 编码、绝对路径这些绕法;有软链接的话还要用 fs.realpathSync 解析后再比。

追问 3ESM 项目里写 __dirname 报 ReferenceError,怎么办?
参考回答

ESM 里没有这个变量。Node 20.11 起可以直接用 import.meta.dirname;老版本写 path.dirname(fileURLToPath(import.meta.url)),fileURLToPath 从 node:url 引入。

追问 4path.resolve 和 path.join 什么时候该用哪个?
参考回答

需要一个确定的绝对路径时用 resolve,比如配置 webpack 的 output.path;只是把几段拼起来,基准已经是 __dirname 这类绝对路径时,用 join 更直观。踩坑最多的是 resolve 的参数里混进一个以 / 开头的片段,前面的全被丢了。

追问 5单测里想验证 Windows 路径的处理结果,但 CI 跑在 Linux 上,怎么写?
参考回答

直接用 path.win32.join('C:\\a', 'b'),结果是 'C:\\a\\b',在任何系统上都按 Windows 规则算。同理 path.posix 固定按 / 处理,生成 URL 路径时也常用它。

# 模块概览

30 秒速记

  • path 只做字符串层面的路径计算,不碰磁盘,不知道文件存不存在
  • 按用途分五组记:拆(dirname / basename / extname)、拼(join / resolve)、规范化(normalize)、分解组合(parse / format)、相对路径(relative)
  • 平台差异是难点:Windows 分隔符是 \、有盘符,POSIX 是 /;默认 path 跟着当前系统走,要固定行为就用 path.posix / path.win32
  • __dirname 只在 CommonJS 里有;ESM 用 fileURLToPath(import.meta.url),Node 20.11+ 可以直接用 import.meta.dirname

path 是 Node.js 里专门算路径字符串的模块,它不读磁盘,只负责把路径拆开、拼起来、算干净。 大家觉得它乱,一是接口多、名字像,二是同一个方法在 Windows 和 Linux

基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
      • 模块概览
      • 获取路径/文件名/扩展名
        • 获取所在路径
        • 获取文件名
        • 获取文件扩展名
      • 路径组合
      • 路径解析
      • path.normalize(filepath)
      • 文件路径分解/组合
      • 获取相对路径
      • 平台相关接口/属性
      • 相关链接
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

本地路径处理 path|Nodejs专题系列

# 本地路径处理 path

30 秒速记

  • path.join 只拼接 + 规范化,结果可能是相对路径;path.resolve 从右往左拼,直到凑出绝对路径,不够就补 process.cwd()
  • join('/a', '/b') = /a/b,resolve('/a', '/b') = /b,这是两者最直观的区别
  • 相对路径默认相对 process.cwd(),不是相对文件所在目录;要稳定就基于 __dirname
  • __dirname 只在 CommonJS 有;ESM 用 import.meta.dirname(Node 20.11+)或 fileURLToPath(import.meta.url)
  • 用户传的路径先 resolve 再检查没逃出根目录,防 ../../etc/passwd

path 模块就是用来正确拼接和解析文件路径的,最常用的是 join 和 resolve,两者看着像,语义不一样。 join 只是把片段用当前系统的分隔符连起来并清理掉 ..、多余斜杠,结果可能还是相对路径;resolve 像在终端里依次 cd,从右往左拼,遇到绝对路径就停,最后还不是绝对路径就补上当前工作目录。写脚本时最常见的坑是相对路径相对的是 process.cwd(),换个目录执行就找不到文件,所以我一般用 path.join(__dirname, 'xxx') 定位。

const path = require('path')
path.join('/a', 'b', '../c')     // '/a/c'
path.join('/a', '/b')            // '/a/b'
path.resolve('/a', '/b')         // '/b'  遇到绝对路径就重新开始
path.resolve('src')              // '/当前工作目录/src'
path.join('src')                 // 'src'  仍是相对路径
@前端进阶之旅: 代码已经复制到剪贴板

理解「本地路径处理 path」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 filesystem 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

path 模块处理的是路径字符串,不碰文件系统,所以它不会告诉你文件存不存在,只负责把路径算对。日常最常用的几个 API:

const path = require('path')
const file = '/home/user/project/src/index.test.js'

path.dirname(file)    // '/home/user/project/src'
path.basename(file)   // 'index.test.js'
path.basename(file, '.js') // 'index.test'
path.extname(file)    // '.js'  只取最后一个点之后的部分
path.parse(file)      // { root: '/', dir: '/home/user/project/src', base: 'index.test.js', ext: '.js', name: 'index.test' }

path.relative('/a/b/c', '/a/d') // '../../d'
path.isAbsolute('./x')          // false
path.sep                        // POSIX 下是 '/',Windows 下是 '\\'
@前端进阶之旅: 代码已经复制到剪贴板

join 和 resolve 的区别可以这样记:join 是「拼字符串再整理」,resolve 是「模拟一路 cd 之后所在的位置」。所以 path.resolve('a', 'b') 会得到 process.cwd() 开头的绝对路径,而 path.join('a', 'b') 只是 a/b。

脚本里定位文件时,最容易出错的是「相对路径到底相对谁」。fs.readFileSync('./config.json') 里的 ./ 相对的是启动进程时所在的目录,不是这个 JS 文件所在的目录。同一个脚本,在项目根目录执行能找到,换到上一级目录执行就找不到。解决办法是基于文件自身位置拼路径:

// CommonJS
const configPath = path.join(__dirname, 'config.json')

// ESM,Node 20.11+
const configPath2 = path.join(import.meta.dirname, 'config.json')

// ESM,更老的版本
import { fileURLToPath } from 'node:url'
const dir = path.dirname(fileURLToPath(import.meta.url))
@前端进阶之旅: 代码已经复制到剪贴板

处理用户输入的路径(比如静态文件服务、上传下载)时,一定要先算出绝对路径,再确认它还在允许的根目录里:

function safeJoin(root, userPath) {
  const target = path.resolve(root, userPath)
  const rel = path.relative(root, target)
  if (rel.startsWith('..') || path.isAbsolute(rel)) throw new Error('非法路径')
  return target
}
safeJoin('/srv/static', 'img/a.png')        // '/srv/static/img/a.png'
safeJoin('/srv/static', '../../etc/passwd') // 抛错
@前端进阶之旅: 代码已经复制到剪贴板

跨平台方面,path 默认按当前系统的规则工作。如果要在 Linux 上测试 Windows 路径,或者需要始终输出 / 分隔的 URL 风格路径,可以显式使用 path.win32 和 path.posix。

面试官追问

追问 1在 macOS 上能找到模板文件,Windows 的 CI 上找不到,常见原因是什么?
参考回答

多半是手拼了 'src/' + name 或写死了 /,再就是文件名大小写,macOS 默认不区分大小写,Linux 区分。拼路径一律用 path.join,比较路径前先 path.normalize。

追问 2用户传了 ../../etc/passwd 当文件名,怎么防?
参考回答

先 const target = path.resolve(root, input),再检查 target.startsWith(root + path.sep),不满足就拒绝。只过滤 .. 字符串不够,还有 URL 编码、绝对路径这些绕法;有软链接的话还要用 fs.realpathSync 解析后再比。

追问 3ESM 项目里写 __dirname 报 ReferenceError,怎么办?
参考回答

ESM 里没有这个变量。Node 20.11 起可以直接用 import.meta.dirname;老版本写 path.dirname(fileURLToPath(import.meta.url)),fileURLToPath 从 node:url 引入。

追问 4path.resolve 和 path.join 什么时候该用哪个?
参考回答

需要一个确定的绝对路径时用 resolve,比如配置 webpack 的 output.path;只是把几段拼起来,基准已经是 __dirname 这类绝对路径时,用 join 更直观。踩坑最多的是 resolve 的参数里混进一个以 / 开头的片段,前面的全被丢了。

追问 5单测里想验证 Windows 路径的处理结果,但 CI 跑在 Linux 上,怎么写?
参考回答

直接用 path.win32.join('C:\\a', 'b'),结果是 'C:\\a\\b',在任何系统上都按 Windows 规则算。同理 path.posix 固定按 / 处理,生成 URL 路径时也常用它。

# 模块概览

30 秒速记

  • path 只做字符串层面的路径计算,不碰磁盘,不知道文件存不存在
  • 按用途分五组记:拆(dirname / basename / extname)、拼(join / resolve)、规范化(normalize)、分解组合(parse / format)、相对路径(relative)
  • 平台差异是难点:Windows 分隔符是 \、有盘符,POSIX 是 /;默认 path 跟着当前系统走,要固定行为就用 path.posix / path.win32
  • __dirname 只在 CommonJS 里有;ESM 用 fileURLToPath(import.meta.url),Node 20.11+ 可以直接用 import.meta.dirname

path 是 Node.js 里专门算路径字符串的模块,它不读磁盘,只负责把路径拆开、拼起来、算干净。 大家觉得它乱,一是接口多、名字像,二是同一个方法在 Windows 和 Linux 上结果不一样。我的记法是按用途分组:拆出目录 / 文件名 / 扩展名、拼路径、规范化、对象和字符串互转、算相对路径。只要记住「它就是个字符串工具」,很多疑问就自然解开了,比如 basename 为什么不判断是不是文件,join 为什么不管路径存不存在。

在nodejs中,path是个使用频率很高,但却让人又爱又恨的模块。部分因为文档说的不够清晰,部分因为接口的平台差异性。

将path的接口按照用途归类,仔细琢磨琢磨,也就没那么费解了。

面试官追问

追问 1路径拆分直接 split('/') 不就完了,为什么要用 path?
参考回答

split('/') 在 Windows 上遇到 C:\a\b.js 直接失效,还处理不了 //、..、结尾斜杠这些情况。path 把这些边界都做好了,自己切字符串迟早会在某个路径格式上翻车。

追问 2path.join('/a', 'b') 返回了 /a/b,那 /a/b 这个目录一定存在吗?
参考回答

不一定,path 从头到尾不碰文件系统。要确认存在得用 fs.stat 或者直接去读,按 ENOENT 错误码处理。

追问 3同一段代码在 Mac 上输出 a/b,在 Windows 上变成 a\b,单测快照全挂了,怎么办?
参考回答

默认的 path 跟着运行平台走,这是正常的。快照里要稳定的路径就显式用 path.posix.join,或者断言前统一 replace(/\\/g, '/')。

追问 4ESM 项目里写 __dirname 报 ReferenceError,怎么拿当前文件所在目录?
参考回答

ESM 没有注入这个变量。通用写法是 path.dirname(fileURLToPath(import.meta.url));Node 20.11+ 可以直接用 import.meta.dirname。

追问 5__dirname 和 process.cwd() 有什么区别?
参考回答

__dirname 是当前这个源文件所在的目录,写死在文件位置上;process.cwd() 是你在哪个目录敲的 node 命令。读模块旁边的模板文件用 __dirname,处理用户传进来的相对路径参数才用 cwd。

# 获取路径/文件名/扩展名

← 基础应用2.0 文件系统操作 fs →

fe